package com.java.compilation;

import com.java.compilation.helper.IDGenerator;
import com.java.compilation.helper.Kind;

import java.util.HashMap;
import java.util.Map;

/**
 * @author chenyang
 */
public class SymbolTable {

    private final Map<String, Symbol> globalMap = new HashMap<>();
    private final Map<String, Symbol> localMap = new HashMap<>();
    private final IDGenerator idGenerator = new IDGenerator();

    /**
     * 开始新的子程序作用域，子程序符号表重置
     */
    public void startSubroutine() {
        localMap.clear();
        idGenerator.clear(Kind.ARG);
        idGenerator.clear(Kind.VAR);
    }

    /**
     * 增加新的标识符，并给他提供一个索引
     *
     * @param name
     * @param type
     * @param kind
     */
    public void define(String name, String type, Kind kind) {
        if (kind == Kind.STATIC || kind == Kind.FIELD) {
            globalMap.put(name, new Symbol(name, type, kind, idGenerator.getAndIncr(kind)));
        } else if (kind == Kind.ARG || kind == Kind.VAR) {
            localMap.put(name, new Symbol(name, type, kind, idGenerator.getAndIncr(kind)));
        }
    }

    /**
     * 已经定义在当前作用域内变量的数量
     *
     * @param kind
     * @return
     */
    public int varCount(Kind kind) {
        if (kind == Kind.VAR || kind == Kind.ARG) {
            return (int) localMap.values().stream().filter(symbol -> symbol.kind == kind).count();
        } else if (kind == Kind.STATIC || kind == Kind.FIELD) {
            return (int) globalMap.values().stream().filter(symbol -> symbol.kind == kind).count();
        }
        return -1;
    }

    /**
     * 返回当前作用域内标识符的种类，如果标识符在当前作用域是未知的，返回None
     *
     * @param name
     * @return
     */
    public Kind kindOf(String name) {
        if (localMap.containsKey(name)) {
            return localMap.get(name).kind;
        }
        if (globalMap.containsKey(name)) {
            return globalMap.get(name).kind;
        }
        return Kind.None;
    }

    /**
     * 返回当前作用域标识符的类型
     *
     * @param name
     * @return
     */
    public String typeOf(String name) {
        if (localMap.containsKey(name)) {
            return localMap.get(name).type;
        }
        if (globalMap.containsKey(name)) {
            return globalMap.get(name).type;
        }
        return null;
    }

    // 返回标识符的索引
    public int indexOf(String name) {
        if (localMap.containsKey(name)) {
            return localMap.get(name).index;
        }
        if (globalMap.containsKey(name)) {
            return globalMap.get(name).index;
        }
        return -1;
    }

    private class Symbol {
        private String name;
        private String type;
        private Kind kind;
        private int index;

        public Symbol(String name, String type, Kind kind, int index) {
            this.name = name;
            this.type = type;
            this.kind = kind;
            this.index = index;
        }

        public String getName() {
            return name;
        }

        public String getType() {
            return type;
        }

        public Kind getKind() {
            return kind;
        }

        public int getIndex() {
            return index;
        }
    }
}
